/*
 * KeyValueImpl_.h
 *
 *  Created on: Aug 3, 2011
 *      Author: yong
 */

#ifndef KEYVALUEIMPL__H_
#define KEYVALUEIMPL__H_
#include <boost/shared_array.hpp>
#include <stdexcept>
#include <algorithm>
#include <cstring>
#include <utility>

#include "Typedef.h"

namespace distrim
{

template<typename K, typename V>
class KeyValue<K, V>
{
public:

	typedef K key_type;
	typedef V value_type;

	typedef const K const_key_type;
	typedef const V const_value_type;

	typedef K* key_pointer;
	typedef const K* const_key_pointer;
	typedef K &key_reference;
	typedef const K &const_key_reference;

	typedef V* value_pointer;
	typedef V& value_reference;
	typedef const V* const_value_pointer;
	typedef const V& const_value_reference;

	typedef value_pointer value_iterator;
	typedef const_value_pointer const_value_iterator;

	typedef size_t size_type;

	KeyValue() :
		m_ptrKey(NULL), m_ptrIterValBegin(NULL), m_ptrIterValEnd(NULL),
				m_valueElemCount(0)
	{
	}

	KeyValue(size_type valueElemCount) :
		m_ptrKey(NULL), m_ptrIterValBegin(NULL), m_ptrIterValEnd(NULL),
				m_valueElemCount(valueElemCount)
	{
	}

	KeyValue(const_key_pointer ptrKey, const_value_pointer ptrValueBegin,
			size_type valueElemCount = 1) :
		m_ptrKey(ptrKey), m_ptrIterValBegin(ptrValueBegin), m_ptrIterValEnd(
				m_ptrIterValBegin + m_valueElemCount), m_valueElemCount(
				valueElemCount)
	{
	}

	// Copy constructor.
	KeyValue(const KeyValue<K, V> &other)
	{
		if (m_valueElemCount != other.GetValueElemCount())
		{
			throw std::invalid_argument("incompatible number of value elements");
		}
		memcpy(this, &other, sizeof(other));
	}

	// = operator, copy content rather than address.
	const KeyValue& operator=(const KeyValue<K, V> &other)
	{
		if (m_valueElemCount != other.GetValueElemCount())
		{
			throw std::invalid_argument("incompatible number of value elements");
		}
		memcpy(this, &other, sizeof(other));
		return *this;
	}

	/**
	 * Clone content from other key-value pair.
	 */
	inline void CloneAll(const KeyValue<K, V> &other)
	{
		CloneKey(other);
		CloneValues(other);
	}
	/**
	 *
	 */
	inline void CloneKey(const KeyValue<K, V> &other)
	{
		*m_ptrKey = other.GetKey();
	}

	inline void CloneValues(const KeyValue<K, V> &other)
	{
		if (m_valueElemCount != other.GetValueElemCount())
		{
			throw std::invalid_argument("incompatible number of value elements");
		}
		// Clone values.
		std::copy(begin(), end(), other.begin());
	}

	// + operator for combine operation.
	virtual const KeyValue& operator+(const KeyValue<K, V> &other)
	{
		if (m_valueElemCount != other.GetValueElemCount())
		{
			throw std::invalid_argument("incompatible number of value elements");
		}
		if (*m_ptrKey != *other.m_ptrKey)
		{
			throw std::logic_error("key is not equal");
		}
		std::transform(begin(), end(), other.begin(), begin(), std::plus<V>());
		return *this;
	}

	// Key operations.
	inline const_key_type GetKey() const
	{
		return *m_ptrKey;
	}

	inline key_type GetKey()
	{
		return *m_ptrKey;
	}

	inline void SetKey(const_key_reference key)
	{
		*m_ptrKey = key;
	}

	inline void SetKeyPtr(key_pointer ptrKey)
	{
		m_ptrKey = ptrKey;
	}

	inline key_pointer GetKeyPtr()
	{
		return m_ptrKey;
	}

	inline const_key_pointer GetKeyPtr() const
	{
		return m_ptrKey;
	}

	inline void SetValueElem(const_value_pointer valueElems,
			size_type valueElemCount)
	{
		if (m_valueElemCount != valueElemCount)
		{
			throw std::invalid_argument("incompatible number of value elements");
		}
		std::copy(valueElems, valueElems + valueElemCount, m_ptrIterValBegin);
	}

	inline void SetValueBegPtr(value_pointer ptrValBeg)
	{
		m_ptrIterValBegin = ptrValBeg;
		m_ptrIterValEnd = m_ptrIterValBegin + m_valueElemCount;
	}

	inline value_pointer GetValueBegPtr()
	{
		return m_ptrIterValBegin;
	}

	inline const_value_pointer GetValueBegPtr() const
	{
		return m_ptrIterValBegin;
	}

	inline value_pointer GetValueEndPtr()
	{
		return m_ptrIterValEnd;
	}

	inline const_value_pointer GetValueEndPtr() const
	{
		return m_ptrIterValEnd;
	}

	inline size_type GetValueElemCount() const
	{
		return m_valueElemCount;
	}
	inline void SetValueElemCount(size_type valueElemCount)
	{
		m_valueElemCount = valueElemCount;
		m_ptrIterValEnd = m_ptrIterValBegin + m_valueElemCount;
	}

	inline const_value_type GetValueElem(size_type idx) const
	{
		return this->operator[](idx);
	}

	/**
	 * Fast value element access support.
	 */
	inline value_reference operator[](size_type idx)
	{
		if (idx < 0 || idx > m_valueElemCount - 1)
		{
			throw std::out_of_range("index of value elem out of range");
		}
		return m_ptrIterValBegin[idx];
	}

	inline const_value_reference operator[](size_type idx) const
	{
		if (idx < 0 || idx > m_valueElemCount - 1)
		{
			throw std::out_of_range("index of value elem out of range");
		}
		return m_ptrIterValBegin[idx];
	}

	inline boost::shared_array<V> GetAllValueElem() const
	{
		V *ptrValues = new V[m_valueElemCount];
		return boost::shared_array<V>(ptrValues);
	}

	/**
	 * Iterator support.
	 */
	inline value_iterator begin()
	{
		return m_ptrIterValBegin;
	}
	inline const_value_iterator begin() const
	{
		return m_ptrIterValBegin;
	}
	inline value_iterator end()
	{
		return m_ptrIterValEnd;
	}
	inline const_value_iterator end() const
	{
		return m_ptrIterValEnd;
	}
	inline size_type size() const
	{
		return m_valueElemCount;
	}

	/**
	 * Sort support.
	 */
	inline bool operator<(const KeyValue<K, V> &other)
	{
		if (m_valueElemCount != other.GetValueElemCount())
		{
			throw std::invalid_argument("incompatible number of value elements");
		}
		return GetKey() < other.GetKey();
	}

	inline bool operator>(const KeyValue<K, V> &other)
	{
		if (m_valueElemCount != other.GetValueElemCount())
		{
			throw std::invalid_argument("incompatible number of value elements");
		}
		return GetKey() > other.GetKey();
	}

	inline bool operator==(const KeyValue<K, V> &other)
	{
		if (m_valueElemCount != other.GetValueElemCount())
		{
			throw std::invalid_argument("incompatible number of value elements");
		}
		std::pair<key_pointer, key_pointer> pr;
		if (GetKey() == other.GetKey())
		{
			pr = std::mismatch(begin(), end(), other.begin());
			if (pr.first == end() && pr.second == other.end())
			{
				return true;
			}
			else
			{
				return false;
			}
		}
		else
		{
			return false;
		}
	}
	inline bool operator!=(const KeyValue<K, V> &other)
	{
		return !(*this == other);
	}

private:

	K* m_ptrKey;

	V* m_ptrIterValBegin;

	V* m_ptrIterValEnd;

	size_t m_valueElemCount;
};
}
#endif /* KEYVALUEIMPL__H_ */
